#include "sw_iic.h"
#include "stm32f1xx_hal.h"
#include "stm32f1xx_ll_gpio.h"
#include "stm32f1xx_ll_bus.h"
#include "cmsis_os.h"

// 根据芯片修改
void delay_us(uint32_t nus)
{
    uint32_t i = 0;
    while (nus--)
    {
        i = 8;
        while (i--);
    }
}

// 控制I2C速度的延时
void SW_Delay(void)
{
    delay_us(10);
}

// 电容触摸芯片IIC接口初始化
void SW_IIC_Init(void)
{
    LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOB);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC);
    LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOD);

    GPIO_InitStruct.Pin = SW_IIC_SDA_PIN;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    LL_GPIO_Init(SW_IIC_SDA_PORT, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = SW_IIC_SCL_PIN;
    GPIO_InitStruct.Mode = LL_GPIO_MODE_OUTPUT;
    GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
    GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
    GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
    LL_GPIO_Init(SW_IIC_SCL_PORT, &GPIO_InitStruct);
    LL_GPIO_SetOutputPin(SW_IIC_SDA_PORT, SW_IIC_SDA_PIN);
    LL_GPIO_SetOutputPin(SW_IIC_SCL_PORT, SW_IIC_SCL_PIN);
}

// 产生IIC起始信号
void SW_IIC_Start(void)
{
    SW_IIC_SDA_OUT(); // sda线输出
    SW_IIC_SDA_SET(1);
    SW_IIC_SCL_SET(1);
    SW_Delay();
    SW_IIC_SDA_SET(0); // START:when CLK is high,DATA change form high to low
    SW_Delay();
    SW_IIC_SCL_SET(0); // 钳住I2C总线，准备发送或接收数据
}

// 产生IIC停止信号
void SW_IIC_Stop(void)
{
    SW_IIC_SDA_OUT(); // sda线输出
    SW_IIC_SCL_SET(0);
    SW_IIC_SDA_SET(0);
    SW_Delay();
    SW_IIC_SCL_SET(1);
    SW_Delay();
    SW_IIC_SDA_SET(1); // STOP:when CLK is high DATA change form low to high
}

// 等待应答信号到来
// 返回值：1，接收应答失败
//         0，接收应答成功
uint8_t SW_IIC_Wait_Ack(void)
{
    uint8_t ucErrTime = 0;
    SW_IIC_SDA_IN(); // SDA设置为输入
    SW_IIC_SDA_SET(1);// 逻辑分析仪这里没拉高
    delay_us(1);
    SW_IIC_SCL_SET(1);
    delay_us(1);
    while (SW_IIC_SDA_GET_STATE())
    {
        ucErrTime++;
        if (ucErrTime > 250)
        {
            SW_IIC_Stop();
            return 1;
        }
    }
    SW_IIC_SCL_SET(0); // 时钟输出0
    return 0;
}

// 产生ACK应答
void SW_IIC_Ack(void)
{
    SW_IIC_SCL_SET(0);
    SW_IIC_SDA_OUT();
    SW_IIC_SDA_SET(0);
    SW_Delay();
    SW_IIC_SCL_SET(1);
    SW_Delay();
    SW_IIC_SCL_SET(0);
}

// 不产生ACK应答
void SW_IIC_NAck(void)
{
    SW_IIC_SCL_SET(0);
    SW_IIC_SDA_OUT();
    SW_IIC_SDA_SET(1);
    SW_Delay();
    SW_IIC_SCL_SET(1);
    SW_Delay();
    SW_IIC_SCL_SET(0);
}

// IIC发送一个字节
void SW_IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;
    SW_IIC_SDA_OUT();
    SW_IIC_SCL_SET(0); // 拉低时钟开始数据传输
    for (t = 0; t < 8; t++)
    {
        SW_IIC_SDA_SET((txd & 0x80) >> 7);
        txd <<= 1;
        SW_IIC_SCL_SET(1);
        SW_Delay();
        SW_IIC_SCL_SET(0);
        SW_Delay();
    }
}

// 读1个字节，ack=1时，发送ACK，ack=0，发送nACK
uint8_t SW_IIC_Read_Byte(unsigned char ack)
{
    uint8_t i, receive = 0;
    SW_IIC_SDA_IN(); // SDA设置为输入
    for (i = 0; i < 8; i++)
    {
        SW_IIC_SCL_SET(0);
        delay_us(30);
        SW_IIC_SCL_SET(1);
        receive <<= 1;
        if (SW_IIC_SDA_GET_STATE())
            receive++;
    }
    if (!ack)
        SW_IIC_NAck(); // 发送nACK
    else
        SW_IIC_Ack(); // 发送ACK
    return receive;
}
